import * as ts from 'typescript';
import fs from 'fs-extra';
import path from 'path';
import { ComponentProp } from '../core/types';

/**
 * TypeScript类型分析器
 * 专门用于分析Vue组件中的TypeScript类型定义
 */
export class TypeAnalyzer {
  /**
   * 分析TypeScript文件中的类型定义
   * @param filePath 类型文件路径
   * @param props 已有的属性列表
   */
  public async analyzeTypeFile(filePath: string, props: ComponentProp[]): Promise<void> {
    try {
      // 检查文件是否存在
      if (!(await fs.pathExists(filePath))) {
        return;
      }
      
      // 读取文件内容
      const content = await fs.readFile(filePath, 'utf-8');
      
      // 解析类型定义
      this.parseTypeDefinitions(content, props);
    } catch (error) {
      console.error(`分析类型文件 ${filePath} 失败:`, error);
    }
  }
  
  /**
   * 从Vue组件中提取Props类型定义
   * @param scriptContent 组件脚本内容
   * @param props 组件属性列表
   * @param isVue3 是否为Vue 3组件
   */
  public analyzeComponentScript(scriptContent: string, props: ComponentProp[], isVue3: boolean): void {
    try {
      if (isVue3) {
        this.analyzeVue3Script(scriptContent, props);
      } else {
        this.analyzeVue2Script(scriptContent, props);
      }
    } catch (error) {
      console.error('分析组件脚本失败:', error);
    }
  }

  /**
   * 分析Vue 3组件脚本
   */
  private analyzeVue3Script(scriptContent: string, props: ComponentProp[]): void {
    // 创建一个临时源文件来分析
    const sourceFile = ts.createSourceFile(
      'temp.ts',
      scriptContent,
      ts.ScriptTarget.Latest,
      true
    );
    
    // 查找 defineProps 调用
    this.findDefineProps(sourceFile, props);
    
    // 查找类型定义
    this.findTypeDefinitions(sourceFile, props);
  }

  /**
   * 查找defineProps调用
   */
  private findDefineProps(node: ts.Node, props: ComponentProp[]): void {
    if (ts.isCallExpression(node) && 
        node.expression.getText() === 'defineProps') {
      
      // 检查是否为泛型调用形式：defineProps<T>()
      if (node.typeArguments && node.typeArguments.length > 0) {
        const typeArg = node.typeArguments[0];
        const typeName = typeArg.getText();
        
        // 记录下我们需要寻找的类型名
        this.propTypeName = typeName;
      }
      // 检查是否为对象字面量形式：defineProps({...})
      else if (node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
        this.extractPropsFromObjectLiteral(node.arguments[0], props);
      }
    }
    
    // 递归遍历子节点
    ts.forEachChild(node, child => this.findDefineProps(child, props));
  }
  
  // 存储找到的Props类型名称
  private propTypeName: string | null = null;
  
  /**
   * 查找类型定义
   */
  private findTypeDefinitions(node: ts.Node, props: ComponentProp[]): void {
    // 如果没有类型名称，不需要继续
    if (!this.propTypeName) return;
    
    // 查找接口或类型别名定义
    if ((ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) && 
        node.name.getText() === this.propTypeName) {
      
      if (ts.isInterfaceDeclaration(node)) {
        this.extractPropsFromInterface(node, props);
      } else if (ts.isTypeAliasDeclaration(node) && ts.isTypeLiteralNode(node.type)) {
        this.extractPropsFromTypeLiteral(node.type, props);
      }
    }
    
    // 递归遍历子节点
    ts.forEachChild(node, child => this.findTypeDefinitions(child, props));
  }
  
  /**
   * 从接口定义中提取属性
   */
  private extractPropsFromInterface(node: ts.InterfaceDeclaration, props: ComponentProp[]): void {
    node.members.forEach(member => {
      if (ts.isPropertySignature(member) && member.name) {
        const propName = this.getPropertyName(member.name);
        if (propName) {
          this.processProperty(propName, member, props);
        }
      }
    });
  }
  
  /**
   * 从类型字面量中提取属性
   */
  private extractPropsFromTypeLiteral(node: ts.TypeLiteralNode, props: ComponentProp[]): void {
    node.members.forEach(member => {
      if (ts.isPropertySignature(member) && member.name) {
        const propName = this.getPropertyName(member.name);
        if (propName) {
          this.processProperty(propName, member, props);
        }
      }
    });
  }
  
  /**
   * 从对象字面量中提取Props
   */
  private extractPropsFromObjectLiteral(obj: ts.ObjectLiteralExpression, props: ComponentProp[]): void {
    obj.properties.forEach(prop => {
      if (ts.isPropertyAssignment(prop) && prop.name) {
        const propName = this.getPropertyName(prop.name);
        if (!propName) return;
        
        // 查找现有属性或创建新属性
        let propInfo = props.find(p => p.name === propName);
        if (!propInfo) {
          propInfo = {
            name: propName,
            type: 'any',
            description: '',
            required: false,
            values: []
          };
          props.push(propInfo);
        }
        
        // 检查属性值是否为对象字面量（包含类型定义）
        if (ts.isObjectLiteralExpression(prop.initializer)) {
          this.extractPropConfig(propInfo, prop.initializer);
        } 
        // 如果值为类型引用，提取类型
        else if (ts.isIdentifier(prop.initializer)) {
          const typeName = prop.initializer.getText();
          propInfo.type = this.mapJsTypeToTs(typeName);
        }
      }
    });
  }
  
  /**
   * 从Vue2 Props配置对象中提取信息
   */
  private extractPropConfig(prop: ComponentProp, obj: ts.ObjectLiteralExpression): void {
    obj.properties.forEach(property => {
      if (!ts.isPropertyAssignment(property)) return;
      
      const propKey = this.getPropertyName(property.name);
      if (!propKey) return;
      
      switch (propKey) {
        case 'type':
          if (ts.isIdentifier(property.initializer)) {
            prop.type = this.mapJsTypeToTs(property.initializer.getText());
          } else if (ts.isArrayLiteralExpression(property.initializer)) {
            const types = property.initializer.elements
              .filter(ts.isIdentifier)
              .map(id => this.mapJsTypeToTs(id.getText()));
            
            if (types.length > 0) {
              prop.type = types.join(' | ');
            }
          }
          break;
          
        case 'required':
          if (ts.isPropertyAssignment(property)) {
            // 使用SyntaxKind检查true/false字面量
            if (property.initializer.kind === ts.SyntaxKind.TrueKeyword) {
              prop.required = true;
            } else if (property.initializer.kind === ts.SyntaxKind.FalseKeyword) {
              prop.required = false;
            }
          }
          break;
          
        case 'default':
          // 提取默认值
          if (ts.isStringLiteral(property.initializer) || 
              ts.isNumericLiteral(property.initializer) ||
              property.initializer.kind === ts.SyntaxKind.TrueKeyword ||
              property.initializer.kind === ts.SyntaxKind.FalseKeyword) {
            prop.defaultValue = property.initializer.getText();
          } 
          // 如果是函数，尝试提取返回值
          else if (ts.isFunctionExpression(property.initializer) || 
                  ts.isArrowFunction(property.initializer)) {
            if (property.initializer.body && ts.isBlock(property.initializer.body)) {
              const returnStmt = property.initializer.body.statements
                .find(stmt => ts.isReturnStatement(stmt)) as ts.ReturnStatement;
              
              if (returnStmt && returnStmt.expression) {
                prop.defaultValue = returnStmt.expression.getText();
              }
            } else if (!ts.isBlock(property.initializer.body)) {
              // 箭头函数的简写形式
              prop.defaultValue = property.initializer.body.getText();
            }
          }
          break;
          
        case 'validator':
          // 从验证器函数尝试提取可能的值
          if ((ts.isFunctionExpression(property.initializer) || 
              ts.isArrowFunction(property.initializer)) && 
              property.initializer.body) {
            
            // 尝试找出验证器中的条件检查
            if (ts.isBlock(property.initializer.body)) {
              const validatorBody = property.initializer.body.getText();
              this.extractValuesFromValidator(validatorBody, prop);
            }
          }
          break;
      }
    });
  }
  
  /**
   * 从验证器函数中提取可能的值
   */
  private extractValuesFromValidator(validatorText: string, prop: ComponentProp): void {
    // 查找数组包含检查
    const arrayIncludesMatch = validatorText.match(/\[((?:'[^']*'|"[^"]*"|`[^`]*`|[^,])+,?\s*)+\]\.includes\(/);
    if (arrayIncludesMatch) {
      const arrayContent = arrayIncludesMatch[1];
      const valuesMatch = arrayContent.match(/(["'`])(.+?)\1/g);
      
      if (valuesMatch && valuesMatch.length > 0) {
        prop.values = valuesMatch.map(v => v.trim());
      }
    }
    
    // 查找OR条件
    const orConditionsMatch = validatorText.match(/val\s*===?\s*(["'`])(.+?)\1(\s*\|\|\s*val\s*===?\s*(["'`])(.+?)\4)*/g);
    if (orConditionsMatch) {
      const values = [];
      const valueRegex = /(["'`])(.+?)\1/g;
      let match;
      
      while ((match = valueRegex.exec(orConditionsMatch[0])) !== null) {
        values.push(match[0]);
      }
      
      if (values.length > 0) {
        prop.values = values;
      }
    }
  }
  
  /**
   * 分析Vue 2组件脚本
   */
  private analyzeVue2Script(scriptContent: string, props: ComponentProp[]): void {
    // 创建临时源文件
    const sourceFile = ts.createSourceFile(
      'temp.ts',
      scriptContent,
      ts.ScriptTarget.Latest,
      true
    );
    
    // 查找props定义
    this.findVue2Props(sourceFile, props);
  }
  
  /**
   * 查找Vue 2组件中的props定义
   */
  private findVue2Props(node: ts.Node, props: ComponentProp[]): void {
    if (ts.isPropertyAssignment(node) && 
        node.name.getText() === 'props') {
      
      // 检查是否为数组形式：props: ['prop1', 'prop2']
      if (ts.isArrayLiteralExpression(node.initializer)) {
        node.initializer.elements.forEach(element => {
          if (ts.isStringLiteral(element)) {
            const propName = element.text;
            
            // 查找或创建属性
            let propInfo = props.find(p => p.name === propName);
            if (!propInfo) {
              propInfo = {
                name: propName,
                type: 'any',
                description: '',
                required: false,
                values: []
              };
              props.push(propInfo);
            }
          }
        });
      }
      // 检查是否为对象形式：props: { prop1: String, prop2: { type: Number } }
      else if (ts.isObjectLiteralExpression(node.initializer)) {
        this.extractPropsFromObjectLiteral(node.initializer, props);
      }
    }
    
    // 递归遍历子节点
    ts.forEachChild(node, child => this.findVue2Props(child, props));
  }
  
  /**
   * 解析类型定义文件
   */
  private parseTypeDefinitions(content: string, props: ComponentProp[]): void {
    // 使用TypeScript编译器API解析类型定义
    const sourceFile = ts.createSourceFile(
      'temp.ts',
      content,
      ts.ScriptTarget.Latest,
      true
    );
    
    // 递归遍历AST
    this.visitTypeNode(sourceFile, props);
  }
  
  /**
   * 递归访问TypeScript AST节点
   */
  private visitTypeNode(node: ts.Node, props: ComponentProp[]): void {
    // 查找可能的Props接口或类型定义
    if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) {
      const name = node.name.getText();
      
      // 检查是否可能是Props类型（按命名约定）
      if (name.includes('Props') || name.endsWith('Props') || name.includes('ComponentProps')) {
        if (ts.isInterfaceDeclaration(node)) {
          this.extractPropsFromInterface(node, props);
        } else if (ts.isTypeAliasDeclaration(node) && ts.isTypeLiteralNode(node.type)) {
          this.extractPropsFromTypeLiteral(node.type, props);
        }
      }
    }
    
    // 递归访问子节点
    ts.forEachChild(node, child => this.visitTypeNode(child, props));
  }
  
  /**
   * 处理属性节点
   */
  private processProperty(propName: string, member: ts.PropertySignature, props: ComponentProp[]): void {
    // 查找或创建属性
    let propInfo = props.find(p => p.name === propName);
    if (!propInfo) {
      propInfo = {
        name: propName,
        type: 'any',
        description: '',
        required: !member.questionToken,
        values: []
      };
      props.push(propInfo);
    } else {
      // 更新现有属性
      propInfo.required = !member.questionToken;
    }
    
    // 提取类型信息
    if (member.type) {
      propInfo.type = member.type.getText();
      
      // 从类型中提取可能的值（枚举类型）
      this.extractValuesFromType(member.type, propInfo);
    }
    
    // 提取JSDoc注释中的信息
    const jsDocs = ts.getJSDocCommentsAndTags(member) as ts.JSDoc[];
    if (jsDocs && jsDocs.length > 0) {
      const jsDoc = jsDocs[0];
      
      // 提取描述
      if (jsDoc.comment && !propInfo.description) {
        propInfo.description = typeof jsDoc.comment === 'string' 
          ? jsDoc.comment 
          : jsDoc.comment.map(c => c.text).join('');
      }
      
      // 提取标签信息
      if (jsDoc.tags) {
        jsDoc.tags.forEach(tag => {
          const tagName = tag.tagName.getText();
          
          if (tagName === 'default' && tag.comment) {
            propInfo.defaultValue = typeof tag.comment === 'string' 
              ? tag.comment 
              : tag.comment.map(c => c.text).join('');
          }
        });
      }
    }
  }
  
  /**
   * 从类型中提取可能的值
   */
  private extractValuesFromType(type: ts.TypeNode, prop: ComponentProp): void {
    if (ts.isUnionTypeNode(type)) {
      const values: string[] = [];
      
      type.types.forEach(unionType => {
        if (ts.isLiteralTypeNode(unionType) && unionType.literal) {
          if (ts.isStringLiteral(unionType.literal)) {
            values.push(`'${unionType.literal.text}'`);
          } else if (ts.isNumericLiteral(unionType.literal)) {
            values.push(unionType.literal.text);
          } else if (unionType.literal.kind === ts.SyntaxKind.TrueKeyword) {
            values.push('true');
          } else if (unionType.literal.kind === ts.SyntaxKind.FalseKeyword) {
            values.push('false');
          }
        }
      });
      
      if (values.length > 0) {
        prop.values = values;
      }
    }
  }
  
  /**
   * 获取属性名
   */
  private getPropertyName(node: ts.PropertyName): string | null {
    if (ts.isIdentifier(node)) {
      return node.text;
    } else if (ts.isStringLiteral(node)) {
      return node.text;
    } else if (ts.isNumericLiteral(node)) {
      return node.text;
    }
    return null;
  }
  
  /**
   * 将JavaScript类型映射到TypeScript类型
   */
  private mapJsTypeToTs(jsType: string): string {
    switch (jsType) {
      case 'String': return 'string';
      case 'Number': return 'number';
      case 'Boolean': return 'boolean';
      case 'Array': return 'any[]';
      case 'Object': return 'object';
      case 'Function': return 'Function';
      case 'Symbol': return 'symbol';
      case 'Date': return 'Date';
      default: return jsType;
    }
  }
} 